home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the 3D Game Programming Gurus / gurus.iso / DirectX / dx9sdkcp.exe / SDK (C++) / Bin / DXUtils / Visual Studio 6.0 Wizards / Source Code / Template / d3dutil.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2002-11-12  |  24.8 KB  |  707 lines

  1. //-----------------------------------------------------------------------------
  2. // File: D3DUtil.cpp
  3. //
  4. // Desc: Shortcut macros and functions for using DX objects
  5. //-----------------------------------------------------------------------------
  6. #define STRICT
  7. $$IF(DLG)
  8. #include "stdafx.h"
  9. $$ENDIF
  10. #include <Windows.h>
  11. #include <WindowsX.h>
  12. #include <tchar.h>
  13. #include <stdio.h>
  14. #include "D3DUtil.h"
  15. #include "DXUtil.h"
  16. #include "D3DX9.h"
  17.  
  18.  
  19.  
  20.  
  21. //-----------------------------------------------------------------------------
  22. // Name: D3DUtil_InitMaterial()
  23. // Desc: Initializes a D3DMATERIAL9 structure, setting the diffuse and ambient
  24. //       colors. It does not set emissive or specular colors.
  25. //-----------------------------------------------------------------------------
  26. VOID D3DUtil_InitMaterial( D3DMATERIAL9& mtrl, FLOAT r, FLOAT g, FLOAT b,
  27.                            FLOAT a )
  28. {
  29.     ZeroMemory( &mtrl, sizeof(D3DMATERIAL9) );
  30.     mtrl.Diffuse.r = mtrl.Ambient.r = r;
  31.     mtrl.Diffuse.g = mtrl.Ambient.g = g;
  32.     mtrl.Diffuse.b = mtrl.Ambient.b = b;
  33.     mtrl.Diffuse.a = mtrl.Ambient.a = a;
  34. }
  35.  
  36.  
  37.  
  38.  
  39. //-----------------------------------------------------------------------------
  40. // Name: D3DUtil_InitLight()
  41. // Desc: Initializes a D3DLIGHT structure, setting the light position. The
  42. //       diffuse color is set to white; specular and ambient are left as black.
  43. //-----------------------------------------------------------------------------
  44. VOID D3DUtil_InitLight( D3DLIGHT9& light, D3DLIGHTTYPE ltType,
  45.                         FLOAT x, FLOAT y, FLOAT z )
  46. {
  47.     D3DXVECTOR3 vecLightDirUnnormalized(x, y, z);
  48.     ZeroMemory( &light, sizeof(D3DLIGHT9) );
  49.     light.Type        = ltType;
  50.     light.Diffuse.r   = 1.0f;
  51.     light.Diffuse.g   = 1.0f;
  52.     light.Diffuse.b   = 1.0f;
  53.     D3DXVec3Normalize( (D3DXVECTOR3*)&light.Direction, &vecLightDirUnnormalized );
  54.     light.Position.x   = x;
  55.     light.Position.y   = y;
  56.     light.Position.z   = z;
  57.     light.Range        = 1000.0f;
  58. }
  59.  
  60.  
  61.  
  62.  
  63. //-----------------------------------------------------------------------------
  64. // Name: D3DUtil_CreateTexture()
  65. // Desc: Helper function to create a texture. It checks the root path first,
  66. //       then tries the DXSDK media path (as specified in the system registry).
  67. //-----------------------------------------------------------------------------
  68. HRESULT D3DUtil_CreateTexture( LPDIRECT3DDEVICE9 pd3dDevice, TCHAR* strTexture,
  69.                                LPDIRECT3DTEXTURE9* ppTexture, D3DFORMAT d3dFormat )
  70. {
  71.     HRESULT hr;
  72.     TCHAR strPath[MAX_PATH];
  73.  
  74.     // Get the path to the texture
  75.     if( FAILED( hr = DXUtil_FindMediaFileCb( strPath, sizeof(strPath), strTexture ) ) )
  76.         return hr;
  77.  
  78.     // Create the texture using D3DX
  79.     return D3DXCreateTextureFromFileEx( pd3dDevice, strPath, 
  80.                 D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, d3dFormat, 
  81.                 D3DPOOL_MANAGED, D3DX_FILTER_TRIANGLE|D3DX_FILTER_MIRROR, 
  82.                 D3DX_FILTER_TRIANGLE|D3DX_FILTER_MIRROR, 0, NULL, NULL, ppTexture );
  83. }
  84.  
  85.  
  86.  
  87.  
  88. //-----------------------------------------------------------------------------
  89. // Name: D3DUtil_GetCubeMapViewMatrix()
  90. // Desc: Returns a view matrix for rendering to a face of a cubemap.
  91. //-----------------------------------------------------------------------------
  92. D3DXMATRIX D3DUtil_GetCubeMapViewMatrix( DWORD dwFace )
  93. {
  94.     D3DXVECTOR3 vEyePt   = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
  95.     D3DXVECTOR3 vLookDir;
  96.     D3DXVECTOR3 vUpDir;
  97.  
  98.     switch( dwFace )
  99.     {
  100.         case D3DCUBEMAP_FACE_POSITIVE_X:
  101.             vLookDir = D3DXVECTOR3( 1.0f, 0.0f, 0.0f );
  102.             vUpDir   = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
  103.             break;
  104.         case D3DCUBEMAP_FACE_NEGATIVE_X:
  105.             vLookDir = D3DXVECTOR3(-1.0f, 0.0f, 0.0f );
  106.             vUpDir   = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
  107.             break;
  108.         case D3DCUBEMAP_FACE_POSITIVE_Y:
  109.             vLookDir = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
  110.             vUpDir   = D3DXVECTOR3( 0.0f, 0.0f,-1.0f );
  111.             break;
  112.         case D3DCUBEMAP_FACE_NEGATIVE_Y:
  113.             vLookDir = D3DXVECTOR3( 0.0f,-1.0f, 0.0f );
  114.             vUpDir   = D3DXVECTOR3( 0.0f, 0.0f, 1.0f );
  115.             break;
  116.         case D3DCUBEMAP_FACE_POSITIVE_Z:
  117.             vLookDir = D3DXVECTOR3( 0.0f, 0.0f, 1.0f );
  118.             vUpDir   = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
  119.             break;
  120.         case D3DCUBEMAP_FACE_NEGATIVE_Z:
  121.             vLookDir = D3DXVECTOR3( 0.0f, 0.0f,-1.0f );
  122.             vUpDir   = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
  123.             break;
  124.     }
  125.  
  126.     // Set the view transform for this cubemap surface
  127.     D3DXMATRIXA16 matView;
  128.     D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookDir, &vUpDir );
  129.     return matView;
  130. }
  131.  
  132.  
  133.  
  134.  
  135. //-----------------------------------------------------------------------------
  136. // Name: D3DUtil_GetRotationFromCursor()
  137. // Desc: Returns a quaternion for the rotation implied by the window's cursor
  138. //       position.
  139. //-----------------------------------------------------------------------------
  140. D3DXQUATERNION D3DUtil_GetRotationFromCursor( HWND hWnd,
  141.                                               FLOAT fTrackBallRadius )
  142. {
  143.     POINT pt;
  144.     RECT  rc;
  145.     GetCursorPos( &pt );
  146.     GetClientRect( hWnd, &rc );
  147.     ScreenToClient( hWnd, &pt );
  148.     FLOAT sx = ( ( ( 2.0f * pt.x ) / (rc.right-rc.left) ) - 1 );
  149.     FLOAT sy = ( ( ( 2.0f * pt.y ) / (rc.bottom-rc.top) ) - 1 );
  150.     FLOAT sz;
  151.  
  152.     if( sx == 0.0f && sy == 0.0f )
  153.         return D3DXQUATERNION( 0.0f, 0.0f, 0.0f, 1.0f );
  154.  
  155.     FLOAT d2 = sqrtf( sx*sx + sy*sy );
  156.  
  157.     if( d2 < fTrackBallRadius * 0.70710678118654752440 ) // Inside sphere
  158.         sz = sqrtf( fTrackBallRadius*fTrackBallRadius - d2*d2 );
  159.     else                                                 // On hyperbola
  160.         sz = (fTrackBallRadius*fTrackBallRadius) / (2.0f*d2);
  161.  
  162.     // Get two points on trackball's sphere
  163.     D3DXVECTOR3 p1( sx, sy, sz );
  164.     D3DXVECTOR3 p2( 0.0f, 0.0f, fTrackBallRadius );
  165.  
  166.     // Get axis of rotation, which is cross product of p1 and p2
  167.     D3DXVECTOR3 vAxis;
  168.     D3DXVec3Cross( &vAxis, &p1, &p2);
  169.  
  170.     // Calculate angle for the rotation about that axis
  171.     D3DXVECTOR3 vecDiff = p2-p1;
  172.     FLOAT t = D3DXVec3Length( &vecDiff ) / ( 2.0f*fTrackBallRadius );
  173.     if( t > +1.0f) t = +1.0f;
  174.     if( t < -1.0f) t = -1.0f;
  175.     FLOAT fAngle = 2.0f * asinf( t );
  176.  
  177.     // Convert axis to quaternion
  178.     D3DXQUATERNION quat;
  179.     D3DXQuaternionRotationAxis( &quat, &vAxis, fAngle );
  180.     return quat;
  181. }
  182.  
  183.  
  184.  
  185.  
  186. //-----------------------------------------------------------------------------
  187. // Name: D3DUtil_SetDeviceCursor
  188. // Desc: Gives the D3D device a cursor with image and hotspot from hCursor.
  189. //-----------------------------------------------------------------------------
  190. HRESULT D3DUtil_SetDeviceCursor( LPDIRECT3DDEVICE9 pd3dDevice, HCURSOR hCursor,
  191.                                  BOOL bAddWatermark )
  192. {
  193.     HRESULT hr = E_FAIL;
  194.     ICONINFO iconinfo;
  195.     BOOL bBWCursor;
  196.     LPDIRECT3DSURFACE9 pCursorSurface = NULL;
  197.     HDC hdcColor = NULL;
  198.     HDC hdcMask = NULL;
  199.     HDC hdcScreen = NULL;
  200.     BITMAP bm;
  201.     DWORD dwWidth;
  202.     DWORD dwHeightSrc;
  203.     DWORD dwHeightDest;
  204.     COLORREF crColor;
  205.     COLORREF crMask;
  206.     UINT x;
  207.     UINT y;
  208.     BITMAPINFO bmi;
  209.     COLORREF* pcrArrayColor = NULL;
  210.     COLORREF* pcrArrayMask = NULL;
  211.     DWORD* pBitmap;
  212.     HGDIOBJ hgdiobjOld;
  213.  
  214.     ZeroMemory( &iconinfo, sizeof(iconinfo) );
  215.     if( !GetIconInfo( hCursor, &iconinfo ) )
  216.         goto End;
  217.  
  218.     if (0 == GetObject((HGDIOBJ)iconinfo.hbmMask, sizeof(BITMAP), (LPVOID)&bm))
  219.         goto End;
  220.     dwWidth = bm.bmWidth;
  221.     dwHeightSrc = bm.bmHeight;
  222.  
  223.     if( iconinfo.hbmColor == NULL )
  224.     {
  225.         bBWCursor = TRUE;
  226.         dwHeightDest = dwHeightSrc / 2;
  227.     }
  228.     else 
  229.     {
  230.         bBWCursor = FALSE;
  231.         dwHeightDest = dwHeightSrc;
  232.     }
  233.  
  234.     // Create a surface for the fullscreen cursor
  235.     if( FAILED( hr = pd3dDevice->CreateOffscreenPlainSurface( dwWidth, dwHeightDest, 
  236.         D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &pCursorSurface, NULL ) ) )
  237.     {
  238.         goto End;
  239.     }
  240.  
  241.     pcrArrayMask = new DWORD[dwWidth * dwHeightSrc];
  242.  
  243.     ZeroMemory(&bmi, sizeof(bmi));
  244.     bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
  245.     bmi.bmiHeader.biWidth = dwWidth;
  246.     bmi.bmiHeader.biHeight = dwHeightSrc;
  247.     bmi.bmiHeader.biPlanes = 1;
  248.     bmi.bmiHeader.biBitCount = 32;
  249.     bmi.bmiHeader.biCompression = BI_RGB;
  250.  
  251.     hdcScreen = GetDC( NULL );
  252.     hdcMask = CreateCompatibleDC( hdcScreen );
  253.     if( hdcMask == NULL )
  254.     {
  255.         hr = E_FAIL;
  256.         goto End;
  257.     }
  258.     hgdiobjOld = SelectObject(hdcMask, iconinfo.hbmMask);
  259.     GetDIBits(hdcMask, iconinfo.hbmMask, 0, dwHeightSrc, 
  260.         pcrArrayMask, &bmi, DIB_RGB_COLORS);
  261.     SelectObject(hdcMask, hgdiobjOld);
  262.  
  263.     if (!bBWCursor)
  264.     {
  265.         pcrArrayColor = new DWORD[dwWidth * dwHeightDest];
  266.         hdcColor = CreateCompatibleDC( hdcScreen );
  267.         if( hdcColor == NULL )
  268.         {
  269.             hr = E_FAIL;
  270.             goto End;
  271.         }
  272.         SelectObject(hdcColor, iconinfo.hbmColor);
  273.         GetDIBits(hdcColor, iconinfo.hbmColor, 0, dwHeightDest, 
  274.             pcrArrayColor, &bmi, DIB_RGB_COLORS);
  275.     }
  276.  
  277.     // Transfer cursor image into the surface
  278.     D3DLOCKED_RECT lr;
  279.     pCursorSurface->LockRect( &lr, NULL, 0 );
  280.     pBitmap = (DWORD*)lr.pBits;
  281.     for( y = 0; y < dwHeightDest; y++ )
  282.     {
  283.         for( x = 0; x < dwWidth; x++ )
  284.         {
  285.             if (bBWCursor)
  286.             {
  287.                 crColor = pcrArrayMask[dwWidth*(dwHeightDest-1-y) + x];
  288.                 crMask = pcrArrayMask[dwWidth*(dwHeightSrc-1-y) + x];
  289.             }
  290.             else
  291.             {
  292.                 crColor = pcrArrayColor[dwWidth*(dwHeightDest-1-y) + x];
  293.                 crMask = pcrArrayMask[dwWidth*(dwHeightDest-1-y) + x];
  294.             }
  295.             if (crMask == 0)
  296.                 pBitmap[dwWidth*y + x] = 0xff000000 | crColor;
  297.             else
  298.                 pBitmap[dwWidth*y + x] = 0x00000000;
  299.  
  300.             // It may be helpful to make the D3D cursor look slightly 
  301.             // different from the Windows cursor so you can distinguish 
  302.             // between the two when developing/testing code.  When
  303.             // bAddWatermark is TRUE, the following code adds some
  304.             // small grey "D3D" characters to the upper-left corner of
  305.             // the D3D cursor image.
  306.             if( bAddWatermark && x < 12 && y < 5 )
  307.             {
  308.                 // 11.. 11.. 11.. .... CCC0
  309.                 // 1.1. ..1. 1.1. .... A2A0
  310.                 // 1.1. .1.. 1.1. .... A4A0
  311.                 // 1.1. ..1. 1.1. .... A2A0
  312.                 // 11.. 11.. 11.. .... CCC0
  313.  
  314.                 const WORD wMask[5] = { 0xccc0, 0xa2a0, 0xa4a0, 0xa2a0, 0xccc0 };
  315.                 if( wMask[y] & (1 << (15 - x)) )
  316.                 {
  317.                     pBitmap[dwWidth*y + x] |= 0xff808080;
  318.                 }
  319.             }
  320.         }
  321.     }
  322.     pCursorSurface->UnlockRect();
  323.  
  324.     // Set the device cursor
  325.     if( FAILED( hr = pd3dDevice->SetCursorProperties( iconinfo.xHotspot, 
  326.         iconinfo.yHotspot, pCursorSurface ) ) )
  327.     {
  328.         goto End;
  329.     }
  330.  
  331.     hr = S_OK;
  332.  
  333. End:
  334.     if( iconinfo.hbmMask != NULL )
  335.         DeleteObject( iconinfo.hbmMask );
  336.     if( iconinfo.hbmColor != NULL )
  337.         DeleteObject( iconinfo.hbmColor );
  338.     if( hdcScreen != NULL )
  339.         ReleaseDC( NULL, hdcScreen );
  340.     if( hdcColor != NULL )
  341.         DeleteDC( hdcColor );
  342.     if( hdcMask != NULL )
  343.         DeleteDC( hdcMask );
  344.     SAFE_DELETE_ARRAY( pcrArrayColor );
  345.     SAFE_DELETE_ARRAY( pcrArrayMask );
  346.     SAFE_RELEASE( pCursorSurface );
  347.     return hr;
  348. }
  349.  
  350.  
  351.  
  352. //-----------------------------------------------------------------------------
  353. // Name: D3DFormatToString
  354. // Desc: Returns the string for the given D3DFORMAT.
  355. //-----------------------------------------------------------------------------
  356. TCHAR* D3DUtil_D3DFormatToString( D3DFORMAT format, bool bWithPrefix )
  357. {
  358.     TCHAR* pstr = NULL;
  359.     switch( format )
  360.     {
  361.     case D3DFMT_UNKNOWN:         pstr = TEXT("D3DFMT_UNKNOWN"); break;
  362.     case D3DFMT_R8G8B8:          pstr = TEXT("D3DFMT_R8G8B8"); break;
  363.     case D3DFMT_A8R8G8B8:        pstr = TEXT("D3DFMT_A8R8G8B8"); break;
  364.     case D3DFMT_X8R8G8B8:        pstr = TEXT("D3DFMT_X8R8G8B8"); break;
  365.     case D3DFMT_R5G6B5:          pstr = TEXT("D3DFMT_R5G6B5"); break;
  366.     case D3DFMT_X1R5G5B5:        pstr = TEXT("D3DFMT_X1R5G5B5"); break;
  367.     case D3DFMT_A1R5G5B5:        pstr = TEXT("D3DFMT_A1R5G5B5"); break;
  368.     case D3DFMT_A4R4G4B4:        pstr = TEXT("D3DFMT_A4R4G4B4"); break;
  369.     case D3DFMT_R3G3B2:          pstr = TEXT("D3DFMT_R3G3B2"); break;
  370.     case D3DFMT_A8:              pstr = TEXT("D3DFMT_A8"); break;
  371.     case D3DFMT_A8R3G3B2:        pstr = TEXT("D3DFMT_A8R3G3B2"); break;
  372.     case D3DFMT_X4R4G4B4:        pstr = TEXT("D3DFMT_X4R4G4B4"); break;
  373.     case D3DFMT_A2B10G10R10:     pstr = TEXT("D3DFMT_A2B10G10R10"); break;
  374.     case D3DFMT_A8B8G8R8:        pstr = TEXT("D3DFMT_A8B8G8R8"); break;
  375.     case D3DFMT_X8B8G8R8:        pstr = TEXT("D3DFMT_X8B8G8R8"); break;
  376.     case D3DFMT_G16R16:          pstr = TEXT("D3DFMT_G16R16"); break;
  377.     case D3DFMT_A2R10G10B10:     pstr = TEXT("D3DFMT_A2R10G10B10"); break;
  378.     case D3DFMT_A16B16G16R16:    pstr = TEXT("D3DFMT_A16B16G16R16"); break;
  379.     case D3DFMT_A8P8:            pstr = TEXT("D3DFMT_A8P8"); break;
  380.     case D3DFMT_P8:              pstr = TEXT("D3DFMT_P8"); break;
  381.     case D3DFMT_L8:              pstr = TEXT("D3DFMT_L8"); break;
  382.     case D3DFMT_A8L8:            pstr = TEXT("D3DFMT_A8L8"); break;
  383.     case D3DFMT_A4L4:            pstr = TEXT("D3DFMT_A4L4"); break;
  384.     case D3DFMT_V8U8:            pstr = TEXT("D3DFMT_V8U8"); break;
  385.     case D3DFMT_L6V5U5:          pstr = TEXT("D3DFMT_L6V5U5"); break;
  386.     case D3DFMT_X8L8V8U8:        pstr = TEXT("D3DFMT_X8L8V8U8"); break;
  387.     case D3DFMT_Q8W8V8U8:        pstr = TEXT("D3DFMT_Q8W8V8U8"); break;
  388.     case D3DFMT_V16U16:          pstr = TEXT("D3DFMT_V16U16"); break;
  389.     case D3DFMT_A2W10V10U10:     pstr = TEXT("D3DFMT_A2W10V10U10"); break;
  390.     case D3DFMT_UYVY:            pstr = TEXT("D3DFMT_UYVY"); break;
  391.     case D3DFMT_YUY2:            pstr = TEXT("D3DFMT_YUY2"); break;
  392.     case D3DFMT_DXT1:            pstr = TEXT("D3DFMT_DXT1"); break;
  393.     case D3DFMT_DXT2:            pstr = TEXT("D3DFMT_DXT2"); break;
  394.     case D3DFMT_DXT3:            pstr = TEXT("D3DFMT_DXT3"); break;
  395.     case D3DFMT_DXT4:            pstr = TEXT("D3DFMT_DXT4"); break;
  396.     case D3DFMT_DXT5:            pstr = TEXT("D3DFMT_DXT5"); break;
  397.     case D3DFMT_D16_LOCKABLE:    pstr = TEXT("D3DFMT_D16_LOCKABLE"); break;
  398.     case D3DFMT_D32:             pstr = TEXT("D3DFMT_D32"); break;
  399.     case D3DFMT_D15S1:           pstr = TEXT("D3DFMT_D15S1"); break;
  400.     case D3DFMT_D24S8:           pstr = TEXT("D3DFMT_D24S8"); break;
  401.     case D3DFMT_D24X8:           pstr = TEXT("D3DFMT_D24X8"); break;
  402.     case D3DFMT_D24X4S4:         pstr = TEXT("D3DFMT_D24X4S4"); break;
  403.     case D3DFMT_D16:             pstr = TEXT("D3DFMT_D16"); break;
  404.     case D3DFMT_L16:             pstr = TEXT("D3DFMT_L16"); break;
  405.     case D3DFMT_VERTEXDATA:      pstr = TEXT("D3DFMT_VERTEXDATA"); break;
  406.     case D3DFMT_INDEX16:         pstr = TEXT("D3DFMT_INDEX16"); break;
  407.     case D3DFMT_INDEX32:         pstr = TEXT("D3DFMT_INDEX32"); break;
  408.     case D3DFMT_Q16W16V16U16:    pstr = TEXT("D3DFMT_Q16W16V16U16"); break;
  409.     case D3DFMT_MULTI2_ARGB8:    pstr = TEXT("D3DFMT_MULTI2_ARGB8"); break;
  410.     case D3DFMT_R16F:            pstr = TEXT("D3DFMT_R16F"); break;
  411.     case D3DFMT_G16R16F:         pstr = TEXT("D3DFMT_G16R16F"); break;
  412.     case D3DFMT_A16B16G16R16F:   pstr = TEXT("D3DFMT_A16B16G16R16F"); break;
  413.     case D3DFMT_R32F:            pstr = TEXT("D3DFMT_R32F"); break;
  414.     case D3DFMT_G32R32F:         pstr = TEXT("D3DFMT_G32R32F"); break;
  415.     case D3DFMT_A32B32G32R32F:   pstr = TEXT("D3DFMT_A32B32G32R32F"); break;
  416.     case D3DFMT_CxV8U8:          pstr = TEXT("D3DFMT_CxV8U8"); break;
  417.     default:                     pstr = TEXT("Unknown format"); break;
  418.     }
  419.     if( bWithPrefix || _tcsstr( pstr, TEXT("D3DFMT_") )== NULL )
  420.         return pstr;
  421.     else
  422.         return pstr + lstrlen( TEXT("D3DFMT_") );
  423. }
  424.  
  425.  
  426. //-----------------------------------------------------------------------------
  427. // Name: D3DXQuaternionUnitAxisToUnitAxis2
  428. // Desc: Axis to axis quaternion double angle (no normalization)
  429. //       Takes two points on unit sphere an angle THETA apart, returns
  430. //       quaternion that represents a rotation around cross product by 2*THETA.
  431. //-----------------------------------------------------------------------------
  432. inline D3DXQUATERNION* WINAPI D3DXQuaternionUnitAxisToUnitAxis2
  433. ( D3DXQUATERNION *pOut, const D3DXVECTOR3 *pvFrom, const D3DXVECTOR3 *pvTo)
  434. {
  435.     D3DXVECTOR3 vAxis;
  436.     D3DXVec3Cross(&vAxis, pvFrom, pvTo);    // proportional to sin(theta)
  437.     pOut->x = vAxis.x;
  438.     pOut->y = vAxis.y;
  439.     pOut->z = vAxis.z;
  440.     pOut->w = D3DXVec3Dot( pvFrom, pvTo );
  441.     return pOut;
  442. }
  443.  
  444.  
  445.  
  446.  
  447. //-----------------------------------------------------------------------------
  448. // Name: D3DXQuaternionAxisToAxis
  449. // Desc: Axis to axis quaternion 
  450. //       Takes two points on unit sphere an angle THETA apart, returns
  451. //       quaternion that represents a rotation around cross product by theta.
  452. //-----------------------------------------------------------------------------
  453. inline D3DXQUATERNION* WINAPI D3DXQuaternionAxisToAxis
  454. ( D3DXQUATERNION *pOut, const D3DXVECTOR3 *pvFrom, const D3DXVECTOR3 *pvTo)
  455. {
  456.     D3DXVECTOR3 vA, vB;
  457.     D3DXVec3Normalize(&vA, pvFrom);
  458.     D3DXVec3Normalize(&vB, pvTo);
  459.     D3DXVECTOR3 vHalf(vA + vB);
  460.     D3DXVec3Normalize(&vHalf, &vHalf);
  461.     return D3DXQuaternionUnitAxisToUnitAxis2(pOut, &vA, &vHalf);
  462. }
  463.  
  464.  
  465.  
  466.  
  467. //-----------------------------------------------------------------------------
  468. // Name:
  469. // Desc:
  470. //-----------------------------------------------------------------------------
  471. CD3DArcBall::CD3DArcBall()
  472. {
  473.     Init();
  474. }
  475.  
  476.  
  477.  
  478.  
  479. //-----------------------------------------------------------------------------
  480. // Name:
  481. // Desc:
  482. //-----------------------------------------------------------------------------
  483. void CD3DArcBall::Init()
  484. {
  485.     D3DXQuaternionIdentity( &m_qDown );
  486.     D3DXQuaternionIdentity( &m_qNow );
  487.     D3DXMatrixIdentity( &m_matRotation );
  488.     D3DXMatrixIdentity( &m_matRotationDelta );
  489.     D3DXMatrixIdentity( &m_matTranslation );
  490.     D3DXMatrixIdentity( &m_matTranslationDelta );
  491.     m_bDrag = FALSE;
  492.     m_fRadiusTranslation = 1.0f;
  493.     m_bRightHanded = FALSE;
  494. }
  495.  
  496.  
  497.  
  498.  
  499. //-----------------------------------------------------------------------------
  500. // Name:
  501. // Desc:
  502. //-----------------------------------------------------------------------------
  503. VOID CD3DArcBall::SetWindow( int iWidth, int iHeight, float fRadius )
  504. {
  505.     // Set ArcBall info
  506.     m_iWidth  = iWidth;
  507.     m_iHeight = iHeight;
  508.     m_fRadius = fRadius;
  509. }
  510.  
  511.  
  512.  
  513.  
  514. //-----------------------------------------------------------------------------
  515. // Name:
  516. // Desc:
  517. //-----------------------------------------------------------------------------
  518. D3DXVECTOR3 CD3DArcBall::ScreenToVector( int sx, int sy )
  519. {
  520.     // Scale to screen
  521.     FLOAT x   = -(sx - m_iWidth/2)  / (m_fRadius*m_iWidth/2);
  522.     FLOAT y   =  (sy - m_iHeight/2) / (m_fRadius*m_iHeight/2);
  523.  
  524.     if( m_bRightHanded )
  525.     {
  526.         x = -x;
  527.         y = -y;
  528.     }
  529.  
  530.     FLOAT z   = 0.0f;
  531.     FLOAT mag = x*x + y*y;
  532.  
  533.     if( mag > 1.0f )
  534.     {
  535.         FLOAT scale = 1.0f/sqrtf(mag);
  536.         x *= scale;
  537.         y *= scale;
  538.     }
  539.     else
  540.         z = sqrtf( 1.0f - mag );
  541.  
  542.     // Return vector
  543.     return D3DXVECTOR3( x, y, z );
  544. }
  545.  
  546.  
  547.  
  548.  
  549. //-----------------------------------------------------------------------------
  550. // Name:
  551. // Desc:
  552. //-----------------------------------------------------------------------------
  553. VOID CD3DArcBall::SetRadius( FLOAT fRadius )
  554. {
  555.     m_fRadiusTranslation = fRadius;
  556. }
  557.  
  558.  
  559.  
  560.  
  561. //-----------------------------------------------------------------------------
  562. // Name:
  563. // Desc:
  564. //-----------------------------------------------------------------------------
  565. LRESULT CD3DArcBall::HandleMouseMessages( HWND hWnd, UINT uMsg, WPARAM wParam,
  566.                                           LPARAM lParam )
  567. {
  568.     UNREFERENCED_PARAMETER( hWnd );
  569.  
  570.     static int         iCurMouseX;      // Saved mouse position
  571.     static int         iCurMouseY;
  572.     static D3DXVECTOR3 s_vDown;         // Button down vector
  573.  
  574.     // Current mouse position
  575.     int iMouseX = GET_X_LPARAM(lParam);
  576.     int iMouseY = GET_Y_LPARAM(lParam);
  577.  
  578.     switch( uMsg )
  579.     {
  580.         case WM_RBUTTONDOWN:
  581.         case WM_MBUTTONDOWN:
  582.             // Store off the position of the cursor when the button is pressed
  583.             iCurMouseX = iMouseX;
  584.             iCurMouseY = iMouseY;
  585.             return TRUE;
  586.  
  587.         case WM_LBUTTONDOWN:
  588.             // Start drag mode
  589.             m_bDrag = TRUE;
  590.             s_vDown = ScreenToVector( iMouseX, iMouseY );
  591.             m_qDown = m_qNow;
  592.             return TRUE;
  593.  
  594.         case WM_LBUTTONUP:
  595.             // End drag mode
  596.             m_bDrag = FALSE;
  597.             return TRUE;
  598.  
  599.         case WM_MOUSEMOVE:
  600.             // Drag object
  601.             if( MK_LBUTTON&wParam )
  602.             {
  603.                 if( m_bDrag )
  604.                 {
  605.                     // recompute m_qNow
  606.                     D3DXVECTOR3 vCur = ScreenToVector( iMouseX, iMouseY );
  607.                     D3DXQUATERNION qAxisToAxis;
  608.                     D3DXQuaternionAxisToAxis(&qAxisToAxis, &s_vDown, &vCur);
  609.                     m_qNow = m_qDown;
  610.                     m_qNow *= qAxisToAxis;
  611.                     D3DXMatrixRotationQuaternion(&m_matRotationDelta, &qAxisToAxis);
  612.                 }
  613.                 else
  614.                     D3DXMatrixIdentity(&m_matRotationDelta);
  615.                 D3DXMatrixRotationQuaternion(&m_matRotation, &m_qNow);
  616.                 m_bDrag = TRUE;
  617.             }
  618.             else if( (MK_RBUTTON&wParam) || (MK_MBUTTON&wParam) )
  619.             {
  620.                 // Normalize based on size of window and bounding sphere radius
  621.                 FLOAT fDeltaX = ( iCurMouseX-iMouseX ) * m_fRadiusTranslation / m_iWidth;
  622.                 FLOAT fDeltaY = ( iCurMouseY-iMouseY ) * m_fRadiusTranslation / m_iHeight;
  623.  
  624.                 if( wParam & MK_RBUTTON )
  625.                 {
  626.                     D3DXMatrixTranslation( &m_matTranslationDelta, -2*fDeltaX, 2*fDeltaY, 0.0f );
  627.                     D3DXMatrixMultiply( &m_matTranslation, &m_matTranslation, &m_matTranslationDelta );
  628.                 }
  629.                 else  // wParam & MK_MBUTTON
  630.                 {
  631.                     D3DXMatrixTranslation( &m_matTranslationDelta, 0.0f, 0.0f, 5*fDeltaY );
  632.                     D3DXMatrixMultiply( &m_matTranslation, &m_matTranslation, &m_matTranslationDelta );
  633.                 }
  634.  
  635.                 // Store mouse coordinate
  636.                 iCurMouseX = iMouseX;
  637.                 iCurMouseY = iMouseY;
  638.             }
  639.             return TRUE;
  640.     }
  641.  
  642.     return FALSE;
  643. }
  644.  
  645.  
  646.  
  647.  
  648. //-----------------------------------------------------------------------------
  649. // Name:
  650. // Desc:
  651. //-----------------------------------------------------------------------------
  652. CD3DCamera::CD3DCamera()
  653. {
  654.     // Set attributes for the view matrix
  655.     D3DXVECTOR3 vEyePt(0.0f,0.0f,0.0f);
  656.     D3DXVECTOR3 vLookatPt(0.0f,0.0f,1.0f);
  657.     D3DXVECTOR3 vUpVec(0.0f,1.0f,0.0f);
  658.     SetViewParams( vEyePt, vLookatPt, vUpVec );
  659.  
  660.     // Set attributes for the projection matrix
  661.     SetProjParams( D3DX_PI/4, 1.0f, 1.0f, 1000.0f );
  662. }
  663.  
  664.  
  665.  
  666.  
  667. //-----------------------------------------------------------------------------
  668. // Name:
  669. // Desc:
  670. //-----------------------------------------------------------------------------
  671. VOID CD3DCamera::SetViewParams( D3DXVECTOR3 &vEyePt, D3DXVECTOR3& vLookatPt,
  672.                                 D3DXVECTOR3& vUpVec )
  673. {
  674.     // Set attributes for the view matrix
  675.     m_vEyePt    = vEyePt;
  676.     m_vLookatPt = vLookatPt;
  677.     m_vUpVec    = vUpVec;
  678.     D3DXVECTOR3 vDir = m_vLookatPt - m_vEyePt;
  679.     D3DXVec3Normalize( &m_vView, &vDir );
  680.     D3DXVec3Cross( &m_vCross, &m_vView, &m_vUpVec );
  681.  
  682.     D3DXMatrixLookAtLH( &m_matView, &m_vEyePt, &m_vLookatPt, &m_vUpVec );
  683.     D3DXMatrixInverse( &m_matBillboard, NULL, &m_matView );
  684.     m_matBillboard._41 = 0.0f;
  685.     m_matBillboard._42 = 0.0f;
  686.     m_matBillboard._43 = 0.0f;
  687. }
  688.  
  689.  
  690.  
  691.  
  692. //-----------------------------------------------------------------------------
  693. // Name:
  694. // Desc:
  695. //-----------------------------------------------------------------------------
  696. VOID CD3DCamera::SetProjParams( FLOAT fFOV, FLOAT fAspect, FLOAT fNearPlane,
  697.                                 FLOAT fFarPlane )
  698. {
  699.     // Set attributes for the projection matrix
  700.     m_fFOV        = fFOV;
  701.     m_fAspect     = fAspect;
  702.     m_fNearPlane  = fNearPlane;
  703.     m_fFarPlane   = fFarPlane;
  704.  
  705.     D3DXMatrixPerspectiveFovLH( &m_matProj, fFOV, fAspect, fNearPlane, fFarPlane );
  706. }
  707.